SAML 2.0 Single Sign-On Configuration
Tier: Enterprise
Stirling-PDF supports SAML 2.0 Single Sign-On for enterprise deployments. This allows integration with Identity Providers (IdP) like Okta, Azure AD, Google Workspace, OneLogin, Authentik, and others.
Looking for OAuth 2.0 SSO? See OAuth SSO Configuration (Server tier).
Prerequisitesâ
Before starting, ensure you have:
- Enterprise license active - SAML requires Enterprise tier
- Configs directory mounted - Docker volume mounted (e.g.,
./configs:/configs:ro) - Public backend URL configured - Set
system.backendUrlto your public backend API URL (often same as frontend, verifyhttps://your-domain.com/api/v1/info/statusis accessible) - Reverse proxy configured - Nginx/Traefik/Caddy with X-Forwarded-* headers forwarding
- Login enabled -
security.enableLogin: truein settings - Admin account ready - Either existing admin or plan to use
security.initialLogincredentials - IdP admin access - Access to your SAML Identity Provider (Okta, Azure AD, etc.)
â ī¸ License Requirement: SAML 2.0 authentication requires an ENTERPRISE license. Existing users created before SAML was license-gated are grandfathered and can continue using SAML with any license tier.
đĄ Tip: Start with
loginMethod: allduring initial setup to allow both username/password and SAML login. This ensures you can always access the admin account if SAML configuration needs adjustment.
Setup Guideâ
Follow these steps in order to configure SAML SSO:
Step 1: Setup Certificatesâ
SAML requires 3 certificate files for mutual trust:
| Certificate | Purpose | Action |
|---|---|---|
| SP Private Key | Sign SAML requests to IdP | Generate with OpenSSL |
| SP Certificate | Prove identity to IdP | Generate with OpenSSL, upload to IdP |
| IdP Certificate | Verify SAML responses from IdP | Download from your IdP |
1a. Generate Service Provider (SP) Keypairâ
Stirling-PDF needs a keypair to sign SAML requests and verify responses.
âšī¸ If you don't have a keypair, generate one using OpenSSL:
openssl req -newkey rsa:2048 -nodes \
-keyout private_key.key \
-x509 -days 365 \
-out certificate.crt \
-subj "/C=US/ST=State/L=City/O=Stirling-PDF/CN=your-domain.com"Command explanation:
rsa:2048: Generates 2048-bit RSA key (secure standard)-nodes: No passphrase (required for automated systems)-days 365: Certificate valid for 1 year- Creates two files:
private_key.key(private) andcertificate.crt(public)
If you already have a keypair, ensure you have both the private key and certificate files ready.
1b. Download IdP Certificateâ
- Go to your IdP admin panel
- Find SAML app/provider settings
- Download signing certificate (PEM format)
- Save as
idp-certificate.pem
1c. Place Certificates in Mounted Directoryâ
Place all 3 certificates inside your mounted configs directory:
./configs/
âââ private_key.key â SP private key (keep secure!)
âââ certificate.crt â SP certificate (will upload to IdP)
âââ idp-certificate.pem â IdP certificate (downloaded)
â ī¸ Critical: Use absolute paths in configuration:
/configs/filename.pem(nofile:orclasspath:prefix for Docker)
Step 2: Configure Stirling-PDFâ
Configure SAML authentication by providing:
- IdP URLs and certificate - Get these from your Identity Provider (obtained from IdP admin panel)
- SP certificates - Point to the certificate files created in Step 1
- Backend URL - Your public backend API URL for SAML callbacks (often same as frontend, e.g.,
https://stirling.example.com) - Login settings - Enable login and set method to
all(allows both username/password and SAML during setup)
Key configuration options:
autoCreateUser: true- Automatically create user accounts on first SAML loginblockRegistration: false- Allow new SAML users (set totrueto require admin pre-approval)registrationId: stirling- Identifier used in SAML URLs (must match across all URLs)
- settings.yml
- Environment Variables
Edit /configs/settings.yml:
security:
enableLogin: true
loginMethod: all # Keep 'all' during initial setup
saml2:
enabled: true
autoCreateUser: true
blockRegistration: false
registrationId: stirling
# Identity Provider (IdP) URLs (get from your IdP)
idpSingleLoginUrl: https://idp.example.com/saml/login
idpSingleLogoutUrl: https://idp.example.com/saml/logout
idpIssuer: https://idp.example.com/entityid
idpCert: /configs/idp-certificate.pem
# Service Provider (SP) Certificates
privateKey: /configs/private_key.key
spCert: /configs/certificate.crt
# Required for SAML callback URLs
system:
backendUrl: https://stirling.example.com
Add to your docker-compose.yml or Docker run command:
environment:
SYSTEM_BACKENDURL: https://stirling.example.com
SECURITY_ENABLELOGIN: true
SECURITY_LOGINMETHOD: all
SECURITY_SAML2_ENABLED: true
SECURITY_SAML2_AUTOCREATEUSER: true
SECURITY_SAML2_BLOCKREGISTRATION: false
SECURITY_SAML2_REGISTRATIONID: stirling
SECURITY_SAML2_IDPSINGLELOGINURL: https://idp.example.com/saml/login
SECURITY_SAML2_IDPSINGLELOGOUTURL: https://idp.example.com/saml/logout
SECURITY_SAML2_IDPISSUER: https://idp.example.com/entityid
SECURITY_SAML2_IDPCERT: /configs/idp-certificate.pem
SECURITY_SAML2_PRIVATEKEY: /configs/private_key.key
SECURITY_SAML2_SPCERT: /configs/certificate.crt
đĄ Tip: Replace the example URLs (
idp.example.com) with actual values from your Identity Provider.
Additional Configuration: baseUrl for SAML SLOâ
For Single Logout (SLO) to work correctly in production, you must also set the baseUrl property:
- custom_settings.yml
- Environment Variables
Add to /configs/custom_settings.yml:
baseUrl: "https://your-domain.com"
Add to your Docker Compose environment variables:
environment:
baseUrl: "https://your-domain.com"
â ī¸ Important: Both
system.backendUrlandbaseUrlshould be set to your public-facing URL for SAML to work correctly in production.
Step 3: Configure Your Identity Providerâ
Provide your IdP with these Service Provider details:
Entity ID / SP Metadata URL:
https://your-domain.com/saml2/service-provider-metadata/stirling
Assertion Consumer Service (ACS) URL:
https://your-domain.com/login/saml2/sso/stirling
Single Logout (SLO) URL:
https://your-domain.com/logout
đ Important: Replace
stirlingwith yourregistrationIdvalue if you changed it. The registration ID must match in all URLs.
Upload SP Certificate to IdP (Critical Step):
- Open
certificate.crt(your SP public certificate) - In your IdP's SAML app configuration, find "Verification Certificate" or "SP Certificate" field
- Upload or paste
certificate.crtcontents - Save IdP configuration
Without uploading the SP certificate, your IdP cannot verify requests from Stirling-PDF.
Configure NameID and Attributes:
- NameID format:
emailorunspecified - Ensure at least one username attribute is sent:
username,emailaddress,name,upn, oruid
Step 4: Test SAML Loginâ
- Open an incognito/private browser window
- Navigate to
https://your-domain.com - Click "Login via Single Sign-On" button
- You'll be redirected to your IdP login page
- Enter your IdP credentials
- You'll be redirected back to Stirling-PDF
- A new user account is automatically created (if
autoCreateUser: true)
â ī¸ If login fails, check application logs for SAML errors. See Troubleshooting section.
Step 5: Promote SAML User to Adminâ
- Log in with your initial admin account (username/password)
- Go to Settings â User Management
- Find the SAML user account (created during test login)
- Change Role to Admin
- Save
â ī¸ Important: Keep at least one SAML user with admin privileges before switching to SSO-only mode.
Step 6 (Optional): Switch to SSO-Only Modeâ
Once you've verified SAML works and have a SAML admin user:
security:
loginMethod: saml2 # Disables username/password login
Restart Stirling-PDF.
Configuration Referenceâ
Required Propertiesâ
| Property | Description | Example |
|---|---|---|
security.saml2.enabled | Enable SAML 2 authentication | true |
security.saml2.idpSingleLoginUrl | IdP's Single Sign-On URL | https://idp.example.com/sso |
security.saml2.idpSingleLogoutUrl | IdP's Single Logout URL | https://idp.example.com/slo |
security.saml2.idpIssuer | IdP's Entity ID / Issuer | https://idp.example.com |
security.saml2.idpCert | IdP's signing certificate (PEM format) | /configs/idp-cert.pem |
security.saml2.privateKey | Your SP private key | /configs/private_key.key |
security.saml2.spCert | Your SP certificate | /configs/certificate.crt |
system.backendUrl | Public HTTPS URL for callbacks | https://stirling.example.com |
Optional Propertiesâ
| Property | Default | Description |
|---|---|---|
security.saml2.autoCreateUser | false | Auto-create users on first SAML login |
security.saml2.blockRegistration | false | Block new users (only allow pre-registered) |
security.saml2.registrationId | stirling | Registration ID (must match ACS URL path) |
security.saml2.provider | null | Optional provider name for logging |
security.loginMethod | all | Login method: all, normal, oauth2, saml2 |
Advanced Configurationâ
SAML Attribute Mappingâ
Stirling-PDF attempts to determine the username in the following priority order:
usernameattributeemailaddressattribute (or full URI:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress)nameattribute (or full URI:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name)upnattribute (User Principal Name - often used in Active Directory)uidattribute (Unix user ID)- NameID from SAML Subject (fallback if no attributes provided)
Minimum requirement: NameID in the SAML Subject (used as fallback identifier)
Recommended: At least one username attribute from the priority list above
Attribute Debuggingâ
Enable debug logging to see what attributes your IdP is sending:
- custom_settings.yml
- Environment Variables
Add to /configs/custom_settings.yml:
logging:
level:
stirling.software.proprietary.security.saml2: DEBUG
LOGGING_LEVEL_STIRLING_SOFTWARE_PROPRIETARY_SECURITY_SAML2=DEBUG
Check logs for:
Extracted SAML Attributes: {username=[john.doe], emailaddress=[[email protected]], ...}
đĄ Note: Currently, Stirling-PDF only uses attributes for username identification. Other attributes (first name, last name, groups, roles) are extracted but not used.
Understanding Registration IDâ
The registrationId is a critical configuration value that becomes part of your SAML URLs:
security:
saml2:
registrationId: stirling # Default value
With registrationId: stirling, your URLs are:
- Metadata:
https://your-domain.com/saml2/service-provider-metadata/stirling - ACS:
https://your-domain.com/login/saml2/sso/stirling
If you change the registration ID:
security:
saml2:
registrationId: mycompany # Custom value
Your URLs become:
- Metadata:
https://your-domain.com/saml2/service-provider-metadata/mycompany - ACS:
https://your-domain.com/login/saml2/sso/mycompany
â ī¸ Critical: If you change
registrationIdafter configuring your IdP, you must update ALL URLs in your IdP configuration. The registration ID must match exactly in all places, or SAML login will fail.
đĄ Recommendation: Keep the default
stirlingvalue unless you have a specific reason to change it (e.g., running multiple Stirling-PDF instances with the same IdP).
Auto-Login Featureâ
Tier: Enterprise
Automatically redirect users to SAML login, bypassing the Stirling-PDF login screen:
premium:
proFeatures:
SSOAutoLogin: true
Behavior:
- Users accessing Stirling-PDF are immediately redirected to IdP
- After 5 failed attempts (configurable via
security.loginAttemptCount), auto-redirect is disabled - Users can still manually access
/loginfor form login ifloginMethod: all
Troubleshootingâ
"SAML requires Enterprise license"â
Cause: SAML authentication requires Enterprise tier license.
Solution:
- Verify valid Enterprise license is configured
- Check
premium.enabled=truein settings - Existing users created before license enforcement are grandfathered
"Invalid SAML response signature"â
Cause: IdP certificate mismatch or incorrect format.
Solution:
- Verify
idpCertfile matches certificate from IdP - Ensure certificate is in PEM format (starts with
-----BEGIN CERTIFICATE-----) - Re-download certificate from IdP
- Check certificate hasn't expired
"ACS URL mismatch"â
Cause: Redirect URL doesn't match IdP configuration.
Solution:
- Verify
SYSTEM_BACKENDURLis set to public HTTPS URL - Check reverse proxy sends X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port headers
- Ensure
registrationIdmatches in both URL and configuration - Update ACS URL in IdP to match:
https://your-domain.com/login/saml2/sso/stirling
"File not found: idp-certificate.pem"â
Cause: Certificate file path is incorrect.
Solution:
- Verify file exists at specified path
- For Docker: ensure volume is mounted correctly
- Use absolute paths like
/configs/filename.pem(nofile:prefix) - Check file permissions (must be readable by application)
"Cannot auto-create user"â
Cause: User doesn't exist and auto-creation is disabled.
Solution:
- Set
autoCreateUser: trueto allow new users - Or pre-create user accounts as admin
- Check license allows additional users
"Redirect loop after SAML login"â
Cause: Session or cookie issues.
Solution:
- Clear browser cookies
- Check
SYSTEM_BACKENDURLmatches actual access URL - Verify cookies are allowed for domain
- Ensure SameSite cookie settings are compatible
"Invalid username" errorâ
Cause: No valid username found in assertion.
Solution:
- Enable debug logging to see what attributes are received
- Ensure IdP sends at least one of:
username,emailaddress,name,upn,uid - Verify NameID is present in SAML Subject as fallback
- Check attribute name format (short name vs full URI)
Debug Loggingâ
Enable SAML debug logging to see detailed authentication flow:
- custom_settings.yml
- Environment Variables
Add to /configs/custom_settings.yml:
logging:
level:
org.springframework.security.saml2: DEBUG
org.opensaml: DEBUG
stirling.software.proprietary.security: DEBUG
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY_SAML2=DEBUG
LOGGING_LEVEL_ORG_OPENSAML=DEBUG
LOGGING_LEVEL_STIRLING_SOFTWARE_PROPRIETARY_SECURITY=DEBUG
Check logs for SAML attribute information:
Extracted SAML Attributes: {username=[john.doe], emailaddress=[[email protected]], ...}
Inspect SAML Assertionsâ
Use browser developer tools:
- Open Network tab
- Clear network log
- Attempt SAML login
- Look for POST to
/login/saml2/sso/stirling - Decode SAMLResponse parameter (Base64 + inflate)
Tools:
- SAML-tracer (Firefox/Chrome extension)
- SAML Decoder (online tool)
Known Limitationsâ
idpMetadataUri Not Auto-Populatingâ
The idpMetadataUri configuration field exists but is not currently used to auto-populate IdP settings. You must manually configure:
idpSingleLoginUrlidpSingleLogoutUrlidpIssueridpCert
Workaround: Manually extract values from IdP metadata XML.
đĄ Note: Auto-populating IdP settings from metadata URI is a planned enhancement coming soon.
See Alsoâ
- OAuth SSO Configuration - OAuth 2.0 / OIDC setup
- System and Security - Additional security settings
- External Database - User storage configuration
- Paid Offerings - Enterprise tier and licensing information